package in.ac.dei.edrp.cms.daoimpl.resultprocessing;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import in.ac.dei.edrp.cms.constants.CRConstant;
import in.ac.dei.edrp.cms.daoimpl.activitymaster.StartActivityDaoImpl;
import in.ac.dei.edrp.cms.domain.activitymaster.CountProcessRecorList;
import in.ac.dei.edrp.cms.domain.activitymaster.StartActivityBean;
import in.ac.dei.edrp.cms.domain.registration.prestaging.CourseList;
import in.ac.dei.edrp.cms.domain.resultprocessing.PreProcessCourseList;
import in.ac.dei.edrp.cms.domain.resultprocessing.PreProcessForResultBean;
import in.ac.dei.edrp.cms.utility.PreviousSemesterDetail;

import org.apache.log4j.Logger;
import org.springframework.transaction.support.TransactionTemplate;

import com.ibatis.sqlmap.client.SqlMapClient;

/**
 * Main Purpose of class:
 * 1- Calclates total internal and external marks for a course
 * 2- Calculates aggregate in theory and practical
 * 3- Updates student's status in course by PAS/FAL/REM
 * 4- Update student's semester status by PAS,REM,FAL
 * @author Deepak
 *
 */
public class PreProcessForResult {

	//Object of logger class
	public static final Logger logger = Logger.getLogger(PreProcessForResult.class);
	
	private SqlMapClient sqlMapClient;
	private TransactionTemplate transactionTemplate;
	
	
	public void setSqlMapClient(SqlMapClient sqlMapClient) {
		this.sqlMapClient = sqlMapClient;
	}

	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}



	public PreProcessForResult(SqlMapClient sqlMapClient,TransactionTemplate transactionTemplate){
		this.sqlMapClient=sqlMapClient;
		this.transactionTemplate=transactionTemplate;
	}

	/**
	 * This method prepares list of student to process
	 * @param startActivityBean
	 * @return
	 */
	public CountProcessRecorList startPreProcess(StartActivityBean startActivityBean){
		
		CountProcessRecorList countList=new CountProcessRecorList();
		
		try{
			String universityId=startActivityBean.getUniversityId();
			String entityId=startActivityBean.getEntityId();
			String programId=startActivityBean.getProgramId();
			String branchId=startActivityBean.getBranchId();
			String specializationId=startActivityBean.getSpecializationId();
			String semesterCode=startActivityBean.getSemesterCode();
			String semesterStartDate=startActivityBean.getSemesterStartDate();
			String semesterEndDate=startActivityBean.getSemesterEndDate();
			String sessionStartDate=startActivityBean.getSessionStartDate();
			String sessionEndDate=startActivityBean.getSessionEndDate();
			String programCourseKey=startActivityBean.getProgramCourseKey();
			
			System.out.println(universityId+entityId+programId+branchId+specializationId+semesterCode+
					semesterStartDate+semesterEndDate+sessionStartDate+sessionEndDate+programCourseKey);
			
			PreProcessForResultBean preProcessForResultBean=new PreProcessForResultBean(universityId,entityId,
					programId,branchId,specializationId,semesterCode,semesterStartDate,semesterEndDate,
					sessionStartDate,sessionEndDate,CRConstant.ACTIVE_STATUS,CRConstant.REGISTRATION_STATUS,
					programCourseKey);
			
			int minPassMarks=Integer.parseInt(getMinPassMarks(preProcessForResultBean,"MINMAR"));
			
			int minPassGrade=Integer.parseInt(getMinPassMarks(preProcessForResultBean,"MINGRD"));
			
			//internal weightage factor
			double internalWeight=Double.parseDouble(getMinPassMarks(preProcessForResultBean,"INTWGT"));
			
			//external weightage factor
			double externalWeight=Double.parseDouble(getMinPassMarks(preProcessForResultBean,"EXTWGT"));
			
			
			//prepare list of student's to process marks
			List<PreProcessForResultBean> listOfStudentTOProcess=
				sqlMapClient.queryForList("preprocess.listOfStudentToProcess",preProcessForResultBean);
			
			System.out.println("List of stdent to process: "+listOfStudentTOProcess.size());
			
			//universityID, program course key, semester start date and semester end date in theory course list object
			PreProcessCourseList courseListTheoryData=new PreProcessCourseList(universityId,programCourseKey,
					semesterStartDate,semesterEndDate);
			//setting course classification for Theory Type
			courseListTheoryData.setCourseClassification1("P");
			courseListTheoryData.setCourseClassification2("W");
			
			//setting minimum passing marks and grade
			courseListTheoryData.setMinPassMarks(minPassMarks);
			courseListTheoryData.setMinPassGrade(minPassGrade);
			
			courseListTheoryData.setInternalWeight(internalWeight);
			courseListTheoryData.setExternalWeight(externalWeight);
			
			
			//universityID, program course key, semester start date and semester end date in practical course list object
			PreProcessCourseList courseListPracticalData=new PreProcessCourseList(universityId,programCourseKey,
					semesterStartDate,semesterEndDate);
			//setting course classification for practical type
			courseListPracticalData.setCourseClassification1("C");
			courseListPracticalData.setCourseClassification2("T");
			//setting minimum passing marks and grade
			courseListPracticalData.setMinPassMarks(minPassMarks);
			courseListPracticalData.setMinPassGrade(minPassGrade);
			
			courseListPracticalData.setInternalWeight(internalWeight);
			courseListPracticalData.setExternalWeight(externalWeight);
			
			/******************************************************************
			 * If there will be no change in process of Theory and 
			 * Practical Subjects, then we will use listOfTorP.
			 *****************************************************************/
			List<PreProcessCourseList> listOfTorP=new ArrayList<PreProcessCourseList>();
			listOfTorP.add(courseListTheoryData);
			listOfTorP.add(courseListPracticalData);
			
			for(PreProcessForResultBean listOfStudent:listOfStudentTOProcess){
				
				//Setting roll number and user id in preProcessResultBean object
				preProcessForResultBean.setRollNumber(listOfStudent.getRollNumber());
				preProcessForResultBean.setUserId(startActivityBean.getUserId());
				//Fail subject list
				List<String> failSubjectsList=new ArrayList<String>();
				
				//Pass subject list
				List<String> passSubjectsList=new ArrayList<String>();
				
				/************************************************************************
				 * Computation of theory subjects
				 ************************************************************************/
				//setting roll number of a student with theory data 				
				courseListTheoryData.setRollNumber(listOfStudent.getRollNumber());
				courseListTheoryData.setUserId(startActivityBean.getUserId());
				//courseListTheoryData.setMinPassMarks(70);

				int count=0;
				
				List<PreProcessCourseList> theoryList=sqlMapClient.queryForList("preprocess.getListOfCourseForPRE", courseListTheoryData);
			
				double theoryCredits=0.0;
				double practicalCredits=0.0;
				
				double theoryAggregate=0;
				
				double practicalAggregate=0.0;
				
				int totalTheorySubject=0;
				
				double aggregateTotal=0.0;
				double totalCredits=0.0;
				
				double sgpa=0.0;
				
				//Total evaluation for theoratical marks and theory
				double totalEvaluationForTheory=0.0;
				double totalEvaluationForPractical=0.0;
				
				double totalTheoryCredits=0.0;
				double totalPracticalCredits=0.0;
	
				for(PreProcessCourseList theory:theoryList){
					
					courseListTheoryData.setCourseCode(theory.getCourseCode());
					
					double totalEvaluationMarks=theory.getTotalMarks();
					
					System.out.println("Roll number:"+listOfStudent.getRollNumber()+"Theory Course Code"+theory.getCourseCode()+"FMG="+theory.getFinalMarksOrGrade()+"TM="+theory.getTotalMarks()+"Result System="+theory.getResultSystem()+"CR="+theory.getCredits());					
					
					/******************************************************
					 * Computation according to marks system
					 *****************************************************/
					if(theory.getResultSystem().equalsIgnoreCase("MK")){
						System.out.println("According to marks"+Integer.parseInt(theory.getFinalMarksOrGrade())+" and "+minPassMarks);
						//update total marks in student_marks_summary
						sqlMapClient.update("preprocess.updateStudentMarksSummary", courseListTheoryData);
						//total marks in that course will be compared by minimum passing marks
						//If less than minPassMarks then added as a fail subject and provided credit=0
					if(Integer.parseInt(theory.getFinalMarksOrGrade())<minPassMarks){
						//count++;
						System.out.println("Coming imside fail marks: "+theory.getCourseCode());
						failSubjectsList.add(theory.getCourseCode());
						
					}
					else{
						theoryCredits=theoryCredits+theory.getCredits();
						passSubjectsList.add(theory.getCourseCode());
						courseListTheoryData.setCourseStatus(CRConstant.STATUS_PASS);
						//update status by PASS here
						sqlMapClient.update("preprocess.updateCourseStatus",courseListTheoryData);
						theoryAggregate=theoryAggregate+((Integer.parseInt(theory.getFinalMarksOrGrade())*theory.getCredits()/totalEvaluationMarks));
						
					}
					totalEvaluationForTheory=totalEvaluationForTheory+theory.getCredits();	
												
					}//Marks computation IF ends
					
					/******************************************************
					 * Computation according to grade system
					 *****************************************************/
					if(theory.getResultSystem().equalsIgnoreCase("GR")){
						
						System.out.println("According to marks"+Integer.parseInt(theory.getFinalMarksOrGrade())+" and "+minPassGrade);
						//update final grade in student marks summary
						sqlMapClient.update("preprocess.updateStudentMarksSummary", courseListTheoryData);
						sqlMapClient.update("preprocess.updateStudentMarksSummaryGrade", courseListTheoryData);
						
						PreProcessCourseList preCourseList=new PreProcessCourseList();
						//If final grade value is less than min passing grade value, 
						//then student gets remedial and status will be updated by REM
						//otherwise student course status will be updated by PASS
						
						if(Integer.parseInt(theory.getFinalMarksOrGrade())<minPassGrade){
							//count++;
							System.out.println("Coming imside fail grade: "+theory.getCourseCode());
							failSubjectsList.add(theory.getCourseCode());
						}
						else{
							theoryCredits=theoryCredits+theory.getCredits();
							passSubjectsList.add(theory.getCourseCode());
							courseListTheoryData.setCourseStatus(CRConstant.STATUS_PASS);
							sqlMapClient.update("preprocess.updateCourseStatus",courseListTheoryData);
							sgpa=sgpa+theory.getCredits()*Integer.parseInt(theory.getFinalMarksOrGrade());
							System.out.println("updated by PASS status");
						}
						totalCredits=totalCredits+theory.getCredits();					
					}//GRADE computation IF ends
			
					
					
				}//Course list of theory courses ends
								
								
				/************************************************************************
				 * Computation of practical subjects
				 ************************************************************************/
				//setting roll number of a student with practical data
				courseListPracticalData.setRollNumber(listOfStudent.getRollNumber());
				courseListPracticalData.setUserId(startActivityBean.getUserId());
				//For practical course
				List<PreProcessCourseList> practicalList=sqlMapClient.queryForList("preprocess.getListOfCourseForPRE", courseListPracticalData);
				
				for(PreProcessCourseList practical:practicalList){
					System.out.println("Practical Course Code"+practical.getCourseCode()+"FMG="+practical.getFinalMarksOrGrade()+"TM="+practical.getTotalMarks()+"Result System="+practical.getResultSystem()+"CR="+practical.getCredits()+"=Min pass"+minPassGrade);					
					courseListPracticalData.setCourseCode(practical.getCourseCode());
					
					double totalEvaluationMarks=practical.getTotalMarks();;
										
					if(practical.getResultSystem().equalsIgnoreCase("MK")){
						System.out.println("According to marks"+Integer.parseInt(practical.getFinalMarksOrGrade())+" and "+minPassMarks);
						sqlMapClient.update("preprocess.updateStudentMarksSummary", courseListPracticalData);
						
						if(Integer.parseInt(practical.getFinalMarksOrGrade())<minPassMarks){
							//count++;
							System.out.println("Coming imside fail marks: "+practical.getCourseCode());
							failSubjectsList.add(practical.getCourseCode());
							
						}
						else{
							practicalCredits=practicalCredits+practical.getCredits();
							passSubjectsList.add(practical.getCourseCode());
							courseListPracticalData.setCourseStatus(CRConstant.STATUS_PASS);
							sqlMapClient.update("preprocess.updateCourseStatus",courseListPracticalData);
							practicalAggregate=practicalAggregate+((Integer.parseInt(practical.getFinalMarksOrGrade())*practical.getCredits())/totalEvaluationMarks);
						}
						
						totalEvaluationForPractical=totalEvaluationForPractical+practical.getCredits();
						}
						
						if(practical.getResultSystem().equalsIgnoreCase("GR")){
							
							System.out.println("According to marks"+Integer.parseInt(practical.getFinalMarksOrGrade())+" and "+minPassMarks);
							
							sqlMapClient.update("preprocess.updateStudentMarksSummaryGrade", courseListPracticalData);
							
							if(Integer.parseInt(practical.getFinalMarksOrGrade())<minPassGrade){
								//count++;
								System.out.println("Coming inside fail grade: "+practical.getCourseCode());
								failSubjectsList.add(practical.getCourseCode());
								
							}
							else{
								practicalCredits=practicalCredits+practical.getCredits();
								passSubjectsList.add(practical.getCourseCode());
								courseListPracticalData.setCourseStatus(CRConstant.STATUS_PASS);
								sqlMapClient.update("preprocess.updateCourseStatus",courseListPracticalData);
								sgpa=sgpa+practical.getCredits()*Integer.parseInt(practical.getFinalMarksOrGrade());
							}
							totalCredits=totalCredits+practical.getCredits();
							
						}//Grade computation IF ends
						
						//aggregateTotal=(theoryAggregate+practicalAggregate)/(totalEvaluationForTheory+totalEvaluationForPractical);
						
						//practicalCredits=practicalCredits+practical.getCredits();	
				}//CoursList of practical courses ends
				
				/**********************************************************
				 * PASS/FAIL DECISION CODE
				 **********************************************************/
				preProcessForResultBean.setRollNumber(listOfStudent.getRollNumber());
				int previousSemesterRemedials=0;
				int maxFailSubjects=1;
				int attemptNumber=listOfStudent.getAttemptNumber();
				int maxAttemptAllowed=2;
				//count=failSubjectsList.size();
				
				PreProcessCourseList preProcessCourseList=new PreProcessCourseList(universityId,programCourseKey,
						semesterStartDate,semesterEndDate,listOfStudent.getRollNumber()
						,"Deepak");
					if(failSubjectsList.size() +previousSemesterRemedials >maxFailSubjects){
						if( attemptNumber== maxAttemptAllowed){
							preProcessForResultBean.setProgramStatus(CRConstant.STATUS_FAIL);
							sqlMapClient.update("preprocess.updateStudentProgramStatus", preProcessForResultBean);
							
						}//maxAttempt allowed if ends
						else{
							for(String courseCode:failSubjectsList){
								preProcessCourseList.setCourseCode(courseCode);
								preProcessCourseList.setCourseStatus(CRConstant.STATUS_FAIL);
								sqlMapClient.update("preprocess.updateCourseStatus", preProcessCourseList);
							}//Loop ends for fail courses
							
						//sqlMapClient.update("preprocess.updateSRSHStatus", preProcessForResultBean);
						}//maximum attempt allowed else ends	
						preProcessForResultBean.setSemesterStatus(CRConstant.STATUS_FAIL);
					}else{
					if( failSubjectsList.size()==0){
						preProcessForResultBean.setSemesterStatus(CRConstant.STATUS_PASS);
						if(isFinalSemester(preProcessForResultBean)&&(failSubjectsList.size() +previousSemesterRemedials==0)){
							preProcessForResultBean.setProgramStatus(CRConstant.STATUS_PASS);
							sqlMapClient.update("preprocess.updateStudentProgramStatus", preProcessForResultBean);
						}
							
					}//count=0
						
					if(failSubjectsList.size()>0){
						preProcessForResultBean.setSemesterStatus(CRConstant.STATUS_REMEDIAL);
						//sqlMapClient.update("preprocess.updateSRSHStatus", preProcessForResultBean);
							for(String courseCode:failSubjectsList){
								preProcessCourseList.setCourseCode(courseCode);
								preProcessCourseList.setCourseStatus(CRConstant.STATUS_REMEDIAL);
								sqlMapClient.update("preprocess.updateCourseStatus", preProcessCourseList);
							}//Loop ends for Remedial courses
					}// count!=0 else ends
					}
					//Set theory and practical percentage and credits according to roll number in STUDENT_AGGREGATE
					System.out.println(theoryAggregate+"PA="+practicalAggregate+"TC="+theoryCredits+"PC="+practicalCredits);
					
					preProcessForResultBean.setAggregateTheory(changeNumber(theoryAggregate,totalEvaluationForTheory));
					preProcessForResultBean.setAggregatePractical(changeNumber(practicalAggregate,totalEvaluationForPractical));
					preProcessForResultBean.setWeightedPercentage(changeNumber((theoryAggregate+practicalAggregate),(totalEvaluationForTheory+totalEvaluationForPractical)));
					preProcessForResultBean.setTheoryCredit(theoryCredits);
					preProcessForResultBean.setPracticalCredit(practicalCredits);
					
					if(totalCredits!=0){
						preProcessForResultBean.setSgpa(sgpa/totalCredits);
					}
					
					preProcessForResultBean.setNumberOfRemedials(failSubjectsList.size());
					
					boolean b=findMarksSystem(preProcessForResultBean);
					
					
					String universityMarksSystem=getMinPassMarks(preProcessForResultBean,"RESSYS");
					
					if(b){
					preProcessForResultBean.setRemarks(getRemark((sgpa/totalCredits),changeNumber((theoryAggregate+practicalAggregate),(theoryCredits+practicalCredits)),b,"MK"));
					}
					else{
					preProcessForResultBean.setRemarks(getRemark((sgpa/totalCredits),changeNumber((theoryAggregate+practicalAggregate),(theoryCredits+practicalCredits)),b,universityMarksSystem));
					}
					sqlMapClient.update("preprocess.updateSRSHResultStatus", preProcessForResultBean);
					
					sqlMapClient.update("preprocess.insertStudentAggregate", preProcessForResultBean);
					
			}//processed List of student's for loop ends
			
			
		}catch(Exception e){
			System.out.println("Exception is "+e.getMessage());
			logger.info("Error while computing marks for a student");
		}
		
		return countList;
		
	}

	

	public double changeNumber(double theoryAggregate,
			double totalEvaluationForTheory) {
		// TODO Auto-generated method stub
		System.out.println(theoryAggregate+"="+totalEvaluationForTheory);
		try{
			if(totalEvaluationForTheory==0.0){
				return 0.0;
			}
			else{
				double d=(double)theoryAggregate/(double)totalEvaluationForTheory*100.0;
				System.out.println(d);
				
			return d;
			}
		}catch(Exception e){
			return 0.0;			
		}
		
	}

	public String getRemark(double d,double d1,boolean b,String resultSystem) {
		// TODO Auto-generated method stub
		String remark="NIL";
					
		if(b && resultSystem.equalsIgnoreCase("GR")){
		if(d<3){
			remark="PRF";
		}
		
		if(d>=3 && d<4.5){
			remark="GUD";
		}
		
		if(d>=4.5 && d<6.0){
			remark="VGD";
		}
		
		if(d>=6.0 && d<7.5){
			remark="EXC";
		}
		
		if(d>=7.5 && d<9.0){
			remark="SUP";
		}
		
		if(d>=9.0 && d<10.0){
			remark="EXT";
		}
		}
		else{
			if(d1<33){
				remark="PRF";
			}
		
			if(d1>=33 && d1<45){
				remark="THR";
			}
			
			if(d1>=45 && d1<60){
				remark="SCD";
			}
			
			if(d1>=60 && d1<75){
				remark="FST";
			}
			
			if(d1>=75 && d1<100){
				remark="FSH";
			}
		}
		return remark;
	}

	public boolean findMarksSystem(PreProcessForResultBean preProcessForResultBean) {
		// TODO Auto-generated method stub
		try{
			//Write query for getting that this student is OLD or not
			if(true){
				return true;
			}
			else{
				return false;
			}
			
		}catch(Exception e){
			System.out.println("Exception is: "+e.getMessage());
		}
		return false;
	}

	public boolean isFinalSemester(
			PreProcessForResultBean preProcessForResultBean) {
		// TODO Auto-generated method stub
		boolean finalSemester=false;
		
		try{
			List<PreProcessForResultBean> list=sqlMapClient.queryForList("preprocess.getFinalSemester", preProcessForResultBean);
			
			for(PreProcessForResultBean marks:list){
				if(marks.getSemesterStatus().equalsIgnoreCase("F")){
					finalSemester=true;
				}
			}
		}catch(Exception e){
			System.out.println("Coming inside exception e for final Semester"+e.getMessage());
		}
		return finalSemester;
	}

	public String getMinPassMarks(
			PreProcessForResultBean preProcessForResultBean, String code) {
		// TODO Auto-generated method stub
		
		String minMarks="0";
		preProcessForResultBean.setCode(code);
		
		try{
			List<PreProcessForResultBean> list=sqlMapClient.queryForList("preprocess.getMinPassMarks", preProcessForResultBean);
			
			for(PreProcessForResultBean marks:list){
				minMarks=marks.getMinPassMarks();
			}
			
		}catch(Exception e){
			System.out.println("Coming inside exception "+e.getMessage());
		}
		return minMarks;
	}
	
}
